import { glob } from 'glob';

import { exec, spawn } from 'node:child_process';
import { cpus } from 'node:os';

// 最多可同时运行的子进程数
// const numCpus = cpus().length;
// TODO 20个的时候直接拉满CPU了，只能写小点
const numCpus = Math.min(3, cpus().length);

/**
 * 打包全部页面的工具类
 */
export class PageBuilder {
  constructor() {
    this.restPages = [];
  }

  /**
   * @summary 获取所有匹配的页面路径
   * @description
   * 匹配对象：
   * 【./src/pages/page-a/】
   * 【./src/pages/page-b/】
   * 【./src/pages/page-c/】
   * 避免匹配到：
   * 【./src/pages/】
   * 【./src/pages/xxx/*.js】
   * 【./src/pages/xxx/*.vue】
   * 
   * 所以这里须只匹配到 page 的文件夹
   * 
   * 顶层 await 需要 nodejs 版本支持且
   * package.json 中设置 type 为 module
   * compilerOptions.target 需要为 es2017 及更高
   * 不然这里就得写成函数调用的形式
   */
  async getAllPages() {
    const pages = await glob('./src/pages/*/');
    return pages;
  }

  /**
   * 页面打包
   * @param {String} pagePath 
   */
  async buildPage(pagePath) {
    const pageName = pagePath.replaceAll('\\', '/').split('/').pop();

    // exec 的子进程模式下会缓存标准输出，结束时全部打印出来，所以用 spawn 更适合
    // exec(`pnpm build:page -- target-page=${pageName}`, (err, stdout, stderr) => {
    //   if (err) {
    //     console.error(err);
    //     return;
    //   }
    //   console.log(stdout);
    // });

    const task = spawn(`pnpm build:page -- target-page=${pageName}`, { shell: true });
    // const task = spawn(`echo task=${pageName}`, { shell: true });
    // task.stdout.pipe(process.stdout);
    task.stdout.on('data', (chunk) => {
      console.log(`building ${pageName}:`, chunk.toString());
    });

    task.on("exit", (code) => {
      console.log(`页面打包完成：${pageName}`);

      // 按页面打包，如果还有剩余页面的话，结束一个就再开启一个
      if (this.restPages.length > 0) {
        const takeNext = this.restPages.shift();
        console.log(`待打包页面：${takeNext}`);
        this.buildPage(takeNext);
      }
    });
  }

  /**
   * 根据最大可同时开启进程数进行按页面打包
   * @param {Array} arrPages 
   * @param {Number} maxTaskCountToRun 
   */
  async buildPagesInLimit(arrPages, maxTaskCountToRun) {
    // 首批打包页面
    const buildingPages = arrPages.slice(0, maxTaskCountToRun);
    console.log('buildingPages', buildingPages.length);
    // 剩余的页面
    const restPages = maxTaskCountToRun < numCpus ? [] : arrPages.slice(maxTaskCountToRun);
    this.restPages = restPages;
    console.log('restPages', restPages, restPages.length);

    buildingPages.forEach((pagePath) => this.buildPage(pagePath));
  }

  /**
   * 开始打包
   */
  async startToBuild() {
    const pages = await this.getAllPages();
    const pageCount = pages.length;
    if (pageCount === 0) {
      console.log('No page to build');
    }

    const maxTaskCountToRun = Math.min(numCpus, pages.length);

    await this.buildPagesInLimit(pages, maxTaskCountToRun);
  }
}

(new PageBuilder()).startToBuild();